// v12.v
// Verilog version, rewritten by Li Shen, Aug 2002
// Institute of Computing Technology, Chinese Academy of Sciences
// The original VHDL version is b12.vhd from Politecnico di Torino

module b12 (clock, reset, start, k, speaker, nloss, nl);
input clock;
input reset;
input start;
input [3:0] k;
output speaker;
output nloss;
output [3:0] nl;
/////
wire clock;
wire reset;
wire start;
wire [3:0] k;
reg speaker;
reg nloss;
reg [3:0] nl;
/////
parameter RED= 0, GREEN= 1, YELLOW= 2, BLUE= 3;
parameter LED_ON= 1, LED_OFF= 0;
parameter PLAY_ON= 1, PLAY_OFF= 0;
parameter KEY_ON= 1;
parameter NUM_KEY= 4, COD_COLOR= 2, COD_SOUND= 3;
parameter S_WIN= 4;	//2**COD_COLOR
parameter S_LOSS= 5;	// S_WIN + 1
parameter SIZE_ADDRESS= 5;
parameter SIZE_MEM =32; //2**SIZE_ADDRESS
parameter COUNT_KEY = 33, COUNT_SEQ = 33, DEC_SEQ   = 1, COUNT_FIN = 8;
parameter ERROR_TONE = 1, RED_TONE = 2, GREEN_TONE = 3; 
parameter YELLOW_TONE = 4,  BLUE_TONE = 5, WIN_TONE = 6;
reg wr;
reg [4:0] address;   	//SIZE_MEM - 1 downto 0
reg [1:0] data_in;    	//2**COD_COLOR - 1 downto 0
reg [1:0] data_out;   	//2**COD_COLOR - 1 downto 0
reg [1:0] num;        	//2**COD_COLOR - 1 downto 0
reg [2:0] sound;      	//2**COD_SOUND - 1 downto 0
reg play;
/////
reg s;
reg [2:0] counter;

always @(posedge clock)
begin
    if (reset)
    begin
      s = 0;
      speaker <= 0;
      counter = 0;
    end
    else
      if (play)
         case (sound)
            0:
                if (counter > RED_TONE)
		begin
                   s = ~s;
                   speaker <= s;
                   counter=0;
		end
                else
                   counter= counter + 1;
            1:
                if (counter > GREEN_TONE)
 		begin
                   s = ~s;
                   speaker <= s;
                   counter=0;
		end
                else
                   counter= counter + 1;
            2:
                if (counter > YELLOW_TONE)
  		begin
                   s = ~s;
                   speaker <= s;
                   counter=0;
		end
                else
                   counter= counter + 1;
            3:
                if (counter > BLUE_TONE)
 		begin
                   s = ~s;
                   speaker <= s;
                   counter=0;
		end
                else
                   counter= counter + 1;
            S_WIN:
                if (counter > WIN_TONE)
 		begin
                   s = ~s;
                   speaker <= s;
                   counter=0;
		end
                else
                   counter= counter + 1;
            S_LOSS:
                if (counter > ERROR_TONE)
		begin
                   s = ~s;
                   speaker <= s;
                   counter=0;
		end
                else
                   counter= counter + 1;
            default:
                   counter = 0;
         endcase
      else
      begin
         counter = 0;
         speaker <= 0;
      end
end
/////
reg [1:0] count; //2**COD_COLOR - 1 downto 0

always @(posedge clock)
begin
    if (reset)
    begin
      count = 0;
      num <= 0;
    end
    else
    begin
      count = (count + 1) & 3; // mod 2**COD_COLOR
      num <= count;
    end
end
/////

//RAM is array (natural range SIZE_MEM - 1 downto 0) of
//       natural range 2**COD_COLOR - 1 downto 0
reg [1:0] memory[0:31];	//RAM

always @(posedge clock)
begin
    if (reset)
    begin
	data_out <= 0;
	memory[0]=0; memory[1]=0; memory[2]=0; memory[3]=0;
	memory[4]=0; memory[5]=0; memory[6]=0; memory[7]=0;
	memory[8]=0; memory[9]=0; memory[10]=0; memory[11]=0;
	memory[12]=0; memory[13]=0; memory[14]=0; memory[15]=0;
	memory[16]=0; memory[17]=0; memory[18]=0; memory[19]=0;
	memory[20]=0; memory[21]=0; memory[22]=0; memory[23]=0;
	memory[24]=0; memory[25]=0; memory[26]=0; memory[27]=0;
	memory[28]=0; memory[29]=0; memory[30]=0; memory[31]=0;
    end
    else
    begin
      data_out <= memory[address];
      if (wr)
        memory[address] = data_in;
    end
end

/////

parameter G0=0, G1=1, G2=2, G3=3, G4=4, G5=5, G6=6;
parameter G7=7, G8=8, G9=9, G10=10, G10a=11, G11=12, G12=13;
parameter Ea=14, E0=15, E1=16, K0=17, K1=18, K2=19, K3=20;
parameter K4=21, K5=22, K6=23, W0=24, W1=25;

reg [4:0] gamma;
reg [1:0] ind;		//2**COD_COLOR - 1 downto 0
reg [4:0] scan;		//SIZE_MEM - 1 downto 0
reg [4:0] max;		//SIZE_MEM - 1 downto 0
reg [5:0] timebase;
reg [5:0] count1;

always @(posedge clock)
begin
    if (reset)
    begin
      nloss <= LED_OFF;
      nl <= LED_OFF;
      play <= PLAY_OFF;
      wr <= 0;
      scan = 0 ;
      max = 0 ;
      ind = 0 ;
      timebase = 0 ;
      count1 = 0 ;
      sound <= 0 ;
      address <= 0 ;
      data_in <= 0 ;
      gamma = G0;
    end
    else
    begin
      if (start)
        gamma = G1;
      case (gamma)
      G0: gamma = G0;
      G1:
	begin
          nloss <= LED_OFF;
          nl <= LED_OFF;
          play <= PLAY_OFF;
          wr <= 0;
          max = 0;
          timebase = COUNT_SEQ;
          gamma = G2;
	end
      G2:
	begin
          scan = 0;
          wr <= 1;
          address <= max;
          data_in <= num;
          gamma = G3;
	end
      G3:
	begin
          wr <= 0;
          address <= scan;
          gamma = G4;
	end
      G4: gamma = G5;
      G5:
	begin
          nl[data_out] <= LED_ON;
          count1 = timebase;
          play <= PLAY_ON;
          sound <= data_out;
          gamma = G6;
	end
      G6:
	begin
          if (!count1)
	  begin
            nl <= LED_OFF;
            play <= PLAY_OFF;
            count1 = timebase;
            gamma = G7;
	  end
          else
	  begin
            count1 = count1 - 1;
            gamma = G6;
          end
	end
      G7:
	begin
          if (!count1)
	  begin
            if (scan != max)
	    begin
              scan = scan + 1;
              gamma = G3;
	    end
            else
	    begin
              scan = 0;
              gamma = G8;
	    end
	  end
          else
	  begin
            count1 = count1 - 1;
            gamma = G7;
          end
	end
      G8:
	begin
          count1 = COUNT_KEY;
          address <= scan;
          gamma = G9;
	end
      G9: gamma = G10;
      G10:
	begin
          if (!count1)
	  begin
            nloss <= LED_ON;
            max = 0;
            gamma = K0;
	  end
          else
	  begin
            count1 = count1 - 1;

            if (k[0]==KEY_ON)
	    begin
              ind = 0;	
              sound <= 0;
              play <= PLAY_ON;
              count1 = timebase;
              if (!data_out)
                gamma = G10a;
              else
	      begin
                nloss <= LED_ON;
                gamma = Ea;
              end
	    end
            else if (k[1]==KEY_ON)
	    begin
              ind = 1;	
              sound <= 1;
              play <= PLAY_ON;
              count1 = timebase;
              if (data_out==1)
                gamma = G10a;
              else
	      begin
                nloss <= LED_ON;
                gamma = Ea;
              end
	    end
            else if (k[2]==KEY_ON)
	    begin
              ind = 2;	
              sound <= 2;
              play <= PLAY_ON;
              count1 = timebase;
              if (data_out == 2)
                gamma = G10a;
              else
	      begin
                nloss <= LED_ON;
                gamma = Ea;
              end
	    end
            else if (k[3]==KEY_ON)
	    begin
              ind = 3;	
              sound <= 3;
              play <= PLAY_ON;
              count1 = timebase;
              if (data_out == 3)
                gamma = G10a;
              else
	      begin
                nloss <= LED_ON;
                gamma = Ea;
              end
	    end
            else
               gamma = G10;
          end
	end
      G10a:
	begin
           nl[ind] <= LED_ON;
           gamma = G11;
	end
      G11:
	begin
          if (!count1)
	  begin
            nl <= LED_OFF;
            play <= PLAY_OFF;
            count1 = timebase;		// attiva contatore LED spento
            gamma = G12;               	// stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = G11;               	// stato FSM
          end
	end
      G12:
	begin
          if (!count1)            	// controlla se fine conteggio
	  begin
            if (scan != max)        	// controlla se sequenza non finita
	    begin
              scan = scan + 1;        	// incrementa indirizzo
              gamma = G8;             	// stato FSM
	    end
            else if (max!=(SIZE_MEM-1)) // controlla se memoria non e' esaurita
	    begin
              max = max + 1;            // incrementa registro massima sequenza
              timebase = timebase - DEC_SEQ; // decremento prossima sequenza
              gamma = G2;               // stato FSM
	    end
            else
	    begin
              play <= PLAY_ON;         	// attiva il suono
              sound <= S_WIN;      	// comunica il codice del suono
              count1 = COUNT_FIN;      	// attiva contatore fine suono
              gamma = W0;             	// stato FSM
            end
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = G12;              	// stato FSM
          end
	end
      Ea:
	begin
           nl[ind] <= LED_ON;           // attiva LED tasto
           gamma = E0;                 	// stato FSM
	end
      E0:
	begin
          if (!count1)              	// controlla se fine conteggio
	  begin
            nl <= LED_OFF;   		// spegne LED tasti
            play <= PLAY_OFF;           // disattiva il suono
            count1 = timebase;          // attiva contatore LED spento
            gamma = E1;                 // stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = E0;                 // stato FSM
	  end
	end
      E1:
	begin
          if (!count1)        		// controlla se fine conteggio
	  begin
            max = 0;              	// azzera registro massima sequenza
            gamma = K0;           	// stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;    	// decrementa contatore
            gamma = E1;           	// stato FSM
          end
	end
      K0:
	begin
          address <= max;     	// indirizza ultimo integer range 3 downto 0e
          gamma = K1;        		// stato FSM
	end
      K1:            		// serve per dare tempo per leggere la memoria
          gamma = K2;        		// stato FSM
      K2:
	begin
          nl[data_out] <= LED_ON;    	// attiva LED tasto
          play <= PLAY_ON;           	// attiva suono
          sound <= data_out;     	// comunica il codice del suono
          count1 = timebase;         	// attiva contatore LED acceso
          gamma = K3;               	// stato FSM
	end
      K3:
	begin
          if (!count1)              	// controlla se fine conteggio
	  begin
            nl <= LED_OFF;   		// spegne LED tasti
            play <= PLAY_OFF;           // disattiva il suono
            count1 = timebase;          // attiva contatore LED spento
            gamma = K4;                 // stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = K3;                 // stato FSM
	  end
	end
      K4:
	begin
          if (!count1)             	// controlla se fine conteggio
	  begin
            if (max != scan)         	// controlla se fine lista
	    begin
              max = max + 1;           	// incrementa indirizzo
              gamma = K0;              	// stato FSM
	    end
            else
	    begin
              nl[data_out] <= LED_ON;   // attiva LED tasto
              play <= PLAY_ON;          // attiva suono
              sound <= S_LOSS;      	// codice suono perdita
              count1 = COUNT_FIN;       	// attiva contatore LED acceso
              gamma = K5;              	// stato FSM
            end
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = K4;                	// stato FSM
          end
	end
      K5:
	begin
          if (!count1)             	// controlla se fine conteggio
	  begin
            nl <= LED_OFF;  		// spegne LED tasti
            play <= PLAY_OFF;           // disattiva il suono
            count1 = COUNT_FIN;         // attiva contatore LED spento
            gamma = K6;                	// stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = K5;                	// stato FSM
          end
	end
      K6:
	begin
          if (!count1)           	// controlla se fine conteggio
	  begin
            nl[data_out] <= LED_ON;   	// attiva LED tasto
            play <= PLAY_ON;          	// attiva suono
            sound <= S_LOSS;      	// codice suono perdita
            count1 = COUNT_FIN;       	// attiva contatore LED acceso
            gamma = K5;              	// stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;       	// decrementa contatore
            gamma = K6;              	// stato FSM
          end
	end
      W0:
	begin
          if (!count1)             	// controlla se fine conteggio
	  begin
            nl <= 4'b1111; 		// attiva tutti i LED (LED_ON)
            play <= PLAY_OFF;           // disattiva il suono
            count1 = COUNT_FIN;         // attiva contatore LED acceso
            gamma = W1;                	// stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = W0;                	// stato FSM
          end
	end
      W1:
	begin
          if (!count1)              	// controlla se fine conteggio
	  begin
            nl <= LED_OFF;   		// disattiva tutti i LED
            play <= PLAY_ON;            // attiva il suono
            sound <= S_WIN;          	// comunica il codice del suono
            count1 = COUNT_FIN;         // attiva contatore LED spento
            gamma = W0;                 // stato FSM
	  end
          else
	  begin
            count1 = count1 - 1;        // decrementa contatore
            gamma = W1;                	// stato FSM
          end
	end
      endcase
    end
end
endmodule
